require 'spec_helper'
require 'game_object'

describe GameObject, "movement" do
  before(:each) do
    @obj = GameObject.new
  end
  
  it "should respond to #thrust" do
    @obj.should respond_to(:thrust)
  end
  
  it "should respond to #speed" do
    @obj.should respond_to(:speed)
  end
  
  it "should respond to #max_speed" do
    @obj.should respond_to(:max_speed)
  end
  
  it "should respond to #throttle" do
    @obj.should respond_to(:throttle)
  end
  
  it "should respond to #accelleration" do
    @obj.should respond_to(:accelleration)
  end
  
  it "should accellerate by (thrust * throttle) on #update" do
    game = mock("game")
    throttle_pairs = {
       # throttle => expected accelleration
       1.0 =>  10,
       0.5 =>  5,
       0.0 =>  0,
      -0.5 => -5,
      -1.0 => -10
    }
    
    @obj.thrust = 10
    throttle_pairs.each do |throttle, expected_accelleration|
      @obj.throttle = throttle
      @obj.update(game)
      
      @obj.accelleration.should == expected_accelleration
    end 
  end
  
  it "should have speed increased by accelleration, until max_speed is reached" do
    game = mock("game")
    
    @obj.thrust = 10
    @obj.throttle = 1.0
    @obj.max_speed = 50
    
    1.upto(5) do |i|
      @obj.update(game)
      @obj.speed.should == @obj.thrust * i
    end
    
    # Max speed has been reached, don't increase any more!
    @obj.update(game)
    @obj.speed.should == 50
  end
  
  it "should scale max_speed based on throttle setting" do
    game = mock("game")
    
    @obj.thrust = 10
    @obj.max_speed = 10
    pairs = {
      1.0 => 10,
      0.9 => 9,
      0.5 => 5,
      0.1 => 1,
      0.0 => 0
    }
    
    pairs.each do |throttle, speed|
      @obj.throttle = throttle
      @obj.update(game)
      
      @obj.speed.should == speed
    end
  end
  
  it "should respond to #rotation" do
    @obj.should respond_to(:rotation)
  end
  
  it "should respond to #rotation_speed" do
    @obj.should respond_to(:rotation_speed)
  end
  
  it "should compensate for rotations > 359 and < 0" do
    rotation_pairs = {
      # rotation => expected
       5   => 5,
      -5   => 355,
       360 => 0,
       0   => 0,
       480 => 120,
      -50  => 310,
       10  => 10,
       240 => 240 
    }
    
    rotation_pairs.each do |rotation, expected|
      @obj.rotation = rotation
      @obj.rotation.should == expected
    end
  end
  
  it "should rotate by rotation_speed on #update if turning" do
    game = mock("game")
    @obj.rotation_speed = 5
    
    @obj.rotation_vector = 1
    @obj.update(game)
    @obj.rotation.should == 5
    
    @obj.rotation_vector = -1
    @obj.update(game)
    @obj.rotation.should == 0
    
    @obj.update(game)
    @obj.rotation.should == 355
    
    @obj.rotation_vector = 0
    @obj.update(game)
    @obj.rotation.should == 355
  end
  
  it "should move by speed / tick in direction of rotation" do
    @obj.rotation = 0
    @obj.max_speed = 10
    @obj.thrust = 10
    @obj.throttle = 1
    
    rotations = [0, 45, 90, 180, 270]
    
    game = mock("Game", :null_object => true)
    rotations.each do |r, e|
      v = Vector.new(10, r)
      
      @obj.position = Point.new(0, 0)
      @obj.rotation = r
      @obj.update(game)
      
      @obj.position.to_a.should == v.point.to_a
    end
  end
end